<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="format-detection" content="telephone=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="icon" href="/assets/bear2.png?v=2.1.1" type="image/png" sizes="16x16"><link rel="icon" href="/assets/bear2.png?v=2.1.1" type="image/png" sizes="32x32"><meta name="description" content="C++学习笔记（二）类和对象基础       注：文章是笔者根据郭炜老师的MOOC以及其他材料进行的笔记总结，其中代码示例来自郭炜老师PPT，附上MOOC链接：程序设计与算法（三）转载请注明出处。                     类和对象基础概念                           1、成员函数       成员函数 注意::两个冒号 12int Ca">
<meta property="og:type" content="article">
<meta property="og:title" content="C++学习笔记（二）类和对象基础">
<meta property="og:url" content="http://yoursite.com/2020/08/03/C++%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80/index.html">
<meta property="og:site_name" content="嘉州海棠">
<meta property="og:description" content="C++学习笔记（二）类和对象基础       注：文章是笔者根据郭炜老师的MOOC以及其他材料进行的笔记总结，其中代码示例来自郭炜老师PPT，附上MOOC链接：程序设计与算法（三）转载请注明出处。                     类和对象基础概念                           1、成员函数       成员函数 注意::两个冒号 12int Ca">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-08-03T12:15:01.000Z">
<meta property="article:modified_time" content="2020-08-03T17:22:41.580Z">
<meta property="article:author" content="嘉州海棠">
<meta property="article:tag" content="C&#x2F;C++">
<meta name="twitter:card" content="summary"><title>C++学习笔记（二）类和对象基础 | 嘉州海棠</title><link ref="canonical" href="http://yoursite.com/2020/08/03/C++%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80/"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css" type="text/css"><link rel="stylesheet" href="/css/index.css?v=2.1.1"><script>var Stun = window.Stun || {};
var CONFIG = {
  root: '/',
  algolia: undefined,
  fontIcon: {"prompt":{"success":"fas fa-check-circle","info":"fas fa-arrow-circle-right","warning":"fas fa-exclamation-circle","error":"fas fa-times-circle"},"copyBtn":"fas fa-copy"},
  sidebar: {"offsetTop":"20px","tocMaxDepth":6},
  header: {"enable":true,"showOnPost":false,"scrollDownIcon":true},
  postWidget: {"endText":true},
  nightMode: {"enable":true},
  back2top: {"enable":true},
  codeblock: {"style":"default","highlight":"light","wordWrap":false},
  reward: true,
  fancybox: false,
  zoomImage: {"gapAside":"20px"},
  galleryWaterfall: undefined,
  lazyload: false,
  pjax: undefined,
  externalLink: {"icon":{"enable":true,"name":"fas fa-external-link-alt"}},
  shortcuts: undefined,
  prompt: {"copyButton":"复制","copySuccess":"复制成功","copyError":"复制失败"},
  sourcePath: {"js":"js","css":"css","images":"images"},
};

window.CONFIG = CONFIG;</script><meta name="generator" content="Hexo 5.0.0"><link rel="alternate" href="/atom.xml" title="嘉州海棠" type="application/atom+xml">
</head><body><div class="container" id="container"><header class="header" id="header"><div class="header-inner header-inner--height header-inner--bgcolor"><nav class="header-nav header-nav--sticky"><div class="header-nav-inner"><div class="header-nav-menubtn"><i class="fas fa-bars"></i></div><div class="header-nav-menu"><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/"><span class="header-nav-menu-item__icon"><i class="fas fa-home"></i></span><span class="header-nav-menu-item__text">首页</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/archives/"><span class="header-nav-menu-item__icon"><i class="fas fa-folder-open"></i></span><span class="header-nav-menu-item__text">归档</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/categories/"><span class="header-nav-menu-item__icon"><i class="fas fa-layer-group"></i></span><span class="header-nav-menu-item__text">分类</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/tags/"><span class="header-nav-menu-item__icon"><i class="fas fa-tags"></i></span><span class="header-nav-menu-item__text">标签</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/about/"><span class="header-nav-menu-item__icon"><i class="fas fa-about"></i></span><span class="header-nav-menu-item__text">关于</span></a></div></div><div class="header-nav-search"><span class="header-nav-search__icon"><i class="fas fa-search"></i></span><span class="header-nav-search__text">搜索</span></div><div class="header-nav-mode"><div class="mode"><div class="mode-track"><span class="mode-track-moon"></span><span class="mode-track-sun"></span></div><div class="mode-thumb"></div></div></div></div></nav></div></header><main class="main" id="main"><div class="main-inner"><div class="content-wrap" id="content-wrap"><div class="content" id="content"><!-- Just used to judge whether it is an article page--><div id="is-post"></div><div class="post"><header class="post-header"><h1 class="post-title">C++学习笔记（二）类和对象基础</h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-08-03</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-08-04</span></span></div></header><div class="post-body">
        <h2 id="C-学习笔记（二）类和对象基础"   >
          <a href="#C-学习笔记（二）类和对象基础" class="heading-link"><i class="fas fa-link"></i></a>C++学习笔记（二）类和对象基础</h2>
      <p>注：文章是笔者根据郭炜老师的MOOC以及其他材料进行的笔记总结，其中代码示例来自郭炜老师PPT，附上MOOC链接：<span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="https://www.icourse163.org/course/PKU-1002029030" >程序设计与算法（三）</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span>转载请注明出处。</p>

        <h2 id="类和对象基础概念"   >
          <a href="#类和对象基础概念" class="heading-link"><i class="fas fa-link"></i></a>类和对象基础概念</h2>
      
        <h3 id="1、成员函数"   >
          <a href="#1、成员函数" class="heading-link"><i class="fas fa-link"></i></a>1、成员函数</h3>
      <p>成员函数 注意::两个冒号</p>
<figure class="highlight cpp"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">Car::Size</span><span class="params">()</span></span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>
<p>函数size是Car类的成员函数，只能通过对象、对象指针、对象引用才能调用。</p>
<a id="more"></a>

        <h3 id="2、类的可访问范围"   >
          <a href="#2、类的可访问范围" class="heading-link"><i class="fas fa-link"></i></a>2、类的可访问范围</h3>
      <p>private:私有成员<br>public:公有成员<br>protected:保护成员</p>

        <h3 id="3、类成员的可访问范围"   >
          <a href="#3、类成员的可访问范围" class="heading-link"><i class="fas fa-link"></i></a>3、类成员的可访问范围</h3>
      <p>（1）类成员函数的内部可访问：当前对象和同类其他对象的全部属性，函数。<br>（2）类的成员函数以外可访问该类公有成员。</p>

        <h3 id="4、成员函数重载和参数缺省"   >
          <a href="#4、成员函数重载和参数缺省" class="heading-link"><i class="fas fa-link"></i></a>4、成员函数重载和参数缺省</h3>
      <p>成员函数可以重载和参数缺省，但要避免二义性（无法辨别是函数缺省还是重载）</p>
<figure class="highlight cpp"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">c1ass <span class="title">Location</span> <span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">    <span class="keyword">private</span> :</span></span></span><br><span class="line"><span class="function"><span class="params">        <span class="keyword">int</span> х,y;</span></span></span><br><span class="line"><span class="function"><span class="params">    <span class="keyword">public</span>:</span></span></span><br><span class="line"><span class="function"><span class="params">        <span class="keyword">void</span> init( <span class="keyword">int</span> x =<span class="number">0</span>, <span class="keyword">int</span> y= <span class="number">0</span>) ;    </span></span></span><br><span class="line"><span class="function"><span class="params">        <span class="keyword">void</span> valueX(<span class="keyword">int</span> val=<span class="number">0</span>) ｛x=val;｝</span></span></span><br><span class="line"><span class="function"><span class="params">        <span class="keyword">int</span> valueX() ｛<span class="keyword">return</span> x;&#125;</span></span></span><br><span class="line"><span class="function"><span class="params">];</span></span></span><br><span class="line"><span class="function"><span class="params">  Location A;</span></span></span><br><span class="line"><span class="function"><span class="params">  A.valueX() ; <span class="comment">//编译错误，编译器无法判断调用哪个valueX</span></span></span></span><br></pre></td></tr></table></div></figure>


        <h3 id="5、构造函数"   >
          <a href="#5、构造函数" class="heading-link"><i class="fas fa-link"></i></a>5、构造函数</h3>
      <p>（1）成员函数的一种，名字与类名相同，可以有参数，不能有返回值。<br>（2）对对象进行初始化，给成员变量赋初值。</p>
<figure class="highlight cpp"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Complex</span> ｛</span></span><br><span class="line"><span class="class">        <span class="title">private</span> :</span></span><br><span class="line">            <span class="keyword">double</span> real, imag;</span><br><span class="line">        <span class="keyword">public</span>:</span><br><span class="line">            Complex( <span class="keyword">double</span> r, <span class="keyword">double</span> i= <span class="number">0</span>);</span><br><span class="line">｝;</span><br><span class="line">Complex::Complex( <span class="keyword">double</span> r, <span class="keyword">double</span> i) &#123;</span><br><span class="line">        real= r; imag=i;</span><br><span class="line">&#125;</span><br><span class="line">Complex c1; <span class="comment">//error,缺少枸造函数的参数</span></span><br><span class="line">Complex *pc = <span class="keyword">new</span> Complex; <span class="comment">//error, 缺少参数</span></span><br><span class="line"><span class="function">Complex <span class="title">c1</span><span class="params">(<span class="number">2</span>)</span></span>;<span class="comment">// OK</span></span><br><span class="line">Complex с<span class="number">1</span>(<span class="number">2</span>,<span class="number">4</span>), c2(<span class="number">3</span>,<span class="number">5</span>);<span class="comment">//OK</span></span><br><span class="line">Complex *pc = <span class="keyword">new</span> Complex(<span class="number">3</span>,<span class="number">4</span>);<span class="comment">//OK</span></span><br></pre></td></tr></table></div></figure>
<p>（3）可以有多个构造函数，根据函数重载确定。</p>

        <h3 id="6、复制构造函数"   >
          <a href="#6、复制构造函数" class="heading-link"><i class="fas fa-link"></i></a>6、复制构造函数</h3>
      <p>（1）X::X(const X &amp;)  不写则默认生成。</p>
<figure class="highlight cpp"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Complex c1;<span class="comment">//无参构造函数初始化</span></span><br><span class="line"><span class="function">Complex <span class="title">c2</span><span class="params">(c1)</span></span>;<span class="comment">//复制构造函数初始化</span></span><br><span class="line">Complex c2 = c1;<span class="comment">//初始化，非赋值</span></span><br></pre></td></tr></table></div></figure>
<p>（2）调用复制构造函数情况：<br>一、对象需要另一个对象进行初始化<br>二、函数参数是类A对象，复制构造函数被调用。<br>三、函数返回值是类A对象，复制构造函数被调用。<br>（3）对象间赋值不调用复制构造函数。<br>（4）使用常量引用参数，避免由复制构造函数带来的巨大开销。</p>

        <h3 id="7、类型转换构造函数"   >
          <a href="#7、类型转换构造函数" class="heading-link"><i class="fas fa-link"></i></a>7、类型转换构造函数</h3>
      <p>（1）只有一个参数且不是复制构造函数。<br>（2）自动调用，建立无名的临时对象或临时变量。</p>

        <h3 id="8、析构函数"   >
          <a href="#8、析构函数" class="heading-link"><i class="fas fa-link"></i></a>8、析构函数</h3>
      <p>（1）名字与类名都相同，前面加~，没有参数和返回值，一个类只有一个析构函数。<br>（2）delete时调用析构函数。<br>（3）析构函数在对象作为函数返回值返回后被调用。<br>（4）静态变量生命周期为整个程序运行，因此整个程序退出时才会调用析构函数。</p>
<p><em>欢迎来我的小站玩吖~</em> <span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="https://husterzeming.gitee.io/" >嘉州海棠</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
</div><footer class="post-footer"><div class="post-ending ending"><div class="ending__text">------ 本文结束，感谢您的阅读 ------</div></div><div class="post-copyright copyright"><div class="copyright-author"><span class="copyright-author__name">本文作者: </span><span class="copyright-author__value"><a href="http://yoursite.com">嘉州海棠</a></span></div><div class="copyright-link"><span class="copyright-link__name">本文链接: </span><span class="copyright-link__value"><a href="http://yoursite.com/2020/08/03/C++%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80/">http://yoursite.com/2020/08/03/C++%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80/</a></span></div><div class="copyright-notice"><span class="copyright-notice__name">版权声明: </span><span class="copyright-notice__value">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" rel="external nofollow" target="_blank">BY-NC-SA</a> 许可协议。转载请注明出处！</span></div></div><div class="post-tags"><span class="post-tags-item"><span class="post-tags-item__icon"><i class="fas fa-tag"></i></span><a class="post-tags-item__link" href="http://yoursite.com/tags/C-C/">C/C++</a></span></div><div class="post-reward reward"><div class="reward-button">请我喝杯咖啡~</div><div class="reward-qrcode"><span class="reward-qrcode-alipay"><img class="reward-qrcode-alipay__img" src="/assets/zfb.jpg"><div class="reward-qrcode-alipay__text">支付宝打赏</div></span><span class="reward-qrcode-wechat"><img class="reward-qrcode-wechat__img" src="/assets/wx.jpg"><div class="reward-qrcode-wechat__text">微信打赏</div></span></div></div><nav class="post-paginator paginator"><div class="paginator-next"><a class="paginator-next__link" href="/2020/07/31/C++%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89%20%E4%BB%8EC%E5%88%B0C++/"><span class="paginator-prev__text">C++学习笔记（一） 从C到C++</span><span class="paginator-next__icon"><i class="fas fa-angle-right"></i></span></a></div></nav></footer></div></div></div><div class="sidebar-wrap" id="sidebar-wrap"><aside class="sidebar" id="sidebar"><div class="sidebar-nav"><span class="sidebar-nav-toc current">文章目录</span><span class="sidebar-nav-ov">站点概览</span></div><section class="sidebar-toc"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#C-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80"><span class="toc-number">1.</span> <span class="toc-text">
          C++学习笔记（二）类和对象基础</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5"><span class="toc-number">2.</span> <span class="toc-text">
          类和对象基础概念</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0"><span class="toc-number">2.1.</span> <span class="toc-text">
          1、成员函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E7%B1%BB%E7%9A%84%E5%8F%AF%E8%AE%BF%E9%97%AE%E8%8C%83%E5%9B%B4"><span class="toc-number">2.2.</span> <span class="toc-text">
          2、类的可访问范围</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%E3%80%81%E7%B1%BB%E6%88%90%E5%91%98%E7%9A%84%E5%8F%AF%E8%AE%BF%E9%97%AE%E8%8C%83%E5%9B%B4"><span class="toc-number">2.3.</span> <span class="toc-text">
          3、类成员的可访问范围</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%E3%80%81%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD%E5%92%8C%E5%8F%82%E6%95%B0%E7%BC%BA%E7%9C%81"><span class="toc-number">2.4.</span> <span class="toc-text">
          4、成员函数重载和参数缺省</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5%E3%80%81%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="toc-number">2.5.</span> <span class="toc-text">
          5、构造函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6%E3%80%81%E5%A4%8D%E5%88%B6%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="toc-number">2.6.</span> <span class="toc-text">
          6、复制构造函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7%E3%80%81%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="toc-number">2.7.</span> <span class="toc-text">
          7、类型转换构造函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8%E3%80%81%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0"><span class="toc-number">2.8.</span> <span class="toc-text">
          8、析构函数</span></a></li></ol></li></ol></section><!-- ov = overview--><section class="sidebar-ov hide"><div class="sidebar-ov-author"><div class="sidebar-ov-author__avatar"><img class="sidebar-ov-author__avatar_img" src="/assets/bear.jpg" alt="avatar"></div><p class="sidebar-ov-author__text">热夏 你归来 听蝉</p></div><div class="sidebar-ov-social"><a class="sidebar-ov-social-item" href="https://github.com/HusterZeming" target="_blank" rel="noopener" data-popover="Github" data-popover-pos="up"><span class="sidebar-ov-social-item__icon"><i class="fab fa-github"></i></span></a><a class="sidebar-ov-social-item" href="https://www.zhihu.com/people/jia-zhou-hai-tang" target="_blank" rel="noopener" data-popover="知乎" data-popover-pos="up"><span class="sidebar-ov-social-item__icon">知</span></a><a class="sidebar-ov-social-item" href="la-la-land_" target="_blank" rel="noopener" data-popover="微信" data-popover-pos="up"><span class="sidebar-ov-social-item__icon"><i class="fab fa-weixin"></i></span></a><a class="sidebar-ov-social-item" href="1444865009" target="_blank" rel="noopener" data-popover="QQ" data-popover-pos="up"><span class="sidebar-ov-social-item__icon"><i class="fab fa-qq"></i></span></a></div><div class="sidebar-ov-state"><a class="sidebar-ov-state-item sidebar-ov-state-item--posts" href="/archives/"><div class="sidebar-ov-state-item__count">4</div><div class="sidebar-ov-state-item__name">归档</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--categories" href="/categories/"><div class="sidebar-ov-state-item__count">0</div><div class="sidebar-ov-state-item__name">分类</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--tags" href="/tags/"><div class="sidebar-ov-state-item__count">3</div><div class="sidebar-ov-state-item__name">标签</div></a></div><div class="sidebar-ov-cc"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" target="_blank" rel="noopener" data-popover="知识共享许可协议" data-popover-pos="up"><img src="/images/cc-by-nc-sa.svg"></a></div></section><div class="sidebar-reading"><div class="sidebar-reading-info"><span class="sidebar-reading-info__text">你已阅读了 </span><span class="sidebar-reading-info__num">0</span></div><div class="sidebar-reading-line"></div></div></aside></div><div class="clearfix"></div></div></main><footer class="footer" id="footer"><div class="footer-inner"><div><span>Copyright © 2020</span><span class="footer__icon"><i class="fas fa-heart"></i></span><span>嘉州海棠</span></div><div>半山腰总是拥挤的 | 你得去山顶看看.</div></div></footer><div class="loading-bar" id="loading-bar"><div class="loading-bar__progress"></div></div><div class="back2top" id="back2top"><span class="back2top__icon"><i class="fas fa-rocket"></i></span></div></div><div class="search-mask"></div><div class="search-popup"><span class="search-close"></span><div class="search-input"><input placeholder="搜索文章（支持多关键词，请用空格分隔）"></div><div class="search-results"></div></div><script src="https://cdn.jsdelivr.net/npm/jquery@v3.4.1/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.ui.min.js"></script><script>function initSearch() {
  var isXML = true;
  var search_path = 'search.xml';

  if (!search_path) {
    search_path = 'search.xml';
  } else if (/json$/i.test(search_path)) {
    isXML = false;
  }

  var path = '/' + search_path;
  $.ajax({
    url: path,
    dataType: isXML ? 'xml' : 'json',
    async: true,
    success: function (res) {
      var datas = isXML ? $('entry', res).map(function () {
        // 将 XML 转为 JSON
        return {
          title: $('title', this).text(),
          content: $('content', this).text(),
          url: $('url', this).text()
        };
      }).get() : res;
      var $input = $('.search-input input');
      var $result = $('.search-results');
      // 搜索对象（标题、内容）的权重，影响显示顺序
      var WEIGHT = { title: 100, content: 1 };
      var searchPost = function () {
        var searchText = $input.val().toLowerCase().trim();
        // 根据空白字符分隔关键字
        var keywords = searchText.split(/[\s]+/);
        // 搜索结果
        var matchPosts = [];

        // 有多个关键字时，将原文字整个保存下来
        if (keywords.length > 1) {
          keywords.push(searchText);
        }
        // 防止未输入字符时搜索
        if (searchText.length > 0) {
          datas.forEach(function (data) {
            var isMatch  = false;
            // 没有标题的文章使用预设的 i18n 变量代替
            var title = (data.title && data.title.trim()) || '[ 文章无标题 ]';
            var titleLower = title && title.toLowerCase();
            // 删除 HTML 标签 和 所有空白字符
            var content = data.content && data.content.replace(/<[^>]+>/g, '');
            var contentLower = content && content.toLowerCase();
            // 删除重复的 /
            var postURL = data.url && decodeURI(data.url).replace(/\/{2,}/g, '/');
            // 标题中匹配到的关键词
            var titleHitSlice = [];
            // 内容中匹配到的关键词
            var contentHitSlice = [];

            keywords.forEach(function (keyword) {
              /**
              * 获取匹配的关键词的索引
              * @param {String} keyword 要匹配的关键字
              * @param {String} text 原文字
              * @param {Boolean} caseSensitive 是否区分大小写
              * @param {Number} weight 匹配对象的权重。权重大的优先显示
              * @return {Array}
              */
              function getIndexByword (word, text, caseSensitive, weight) {
                if (!word || !text) {
                  return [];
                };

                var startIndex = 0; // 每次匹配的开始索引
                var index = -1;     // 匹配到的索引值
                var result = [];    // 匹配结果

                if (!caseSensitive) {
                  word = word.toLowerCase();
                  text = text.toLowerCase();
                }

                while((index = text.indexOf(word, startIndex)) !== -1) {
                  var hasMatch = false;
                  // 索引位置相同的关键词，保留长度较长的
                  titleHitSlice.forEach(function (hit) {
                    if (hit.index === index && hit.word.length < word.length) {
                      hit.word = word;
                      hasMatch = true;
                    }
                  });
                  startIndex = index + word.length;
                  !hasMatch && result.push({ index: index, word: word, weight: weight });
                }
                return result;
              }
              titleHitSlice = titleHitSlice.concat(getIndexByword(keyword, titleLower, false, WEIGHT.title));
              contentHitSlice = contentHitSlice.concat(getIndexByword(keyword, contentLower, false, WEIGHT.content));
            });

            var hitTitle = titleHitSlice.length;
            var hitContent = contentHitSlice.length;

            if (hitTitle > 0 || hitContent > 0) {
              isMatch = true;
            }
            if (isMatch) {
              ;[titleHitSlice, contentHitSlice].forEach(function (hit) {
                // 按照匹配文字的索引的递增顺序排序
                hit.sort(function (left, right) {
                  return left.index - right.index;
                });
              });
              /**
              * 给文本中匹配到的关键词添加标记，从而进行高亮显示
              * @param {String} text 原文本
              * @param {Array} hitSlice 匹配项的索引信息
              * @param {Number} start 开始索引
              * @param {Number} end 结束索引
              * @return {String}
              */
              function highlightKeyword (text, hitSlice, start, end) {
                if (!text || !hitSlice || !hitSlice.length) {
                  return;
                }

                var result = '';
                var startIndex = start;
                var endIndex = end;
                hitSlice.forEach(function (hit) {
                  if (hit.index < startIndex) {
                    return;
                  }

                  var hitWordEnd = hit.index + hit.word.length;
                  result += text.slice(startIndex, hit.index);
                  result += '<b>' + text.slice(hit.index, hitWordEnd) + '</b>';
                  startIndex = hitWordEnd;
                });
                result += text.slice(startIndex, endIndex);
                return result;
              }

              var postData = {};
              // 文章总的搜索权重
              var postWeight = titleHitSlice.length * WEIGHT.title + contentHitSlice.length * WEIGHT.content;
              // 标记匹配关键词后的标题
              var postTitle = highlightKeyword(title, titleHitSlice, 0, title.length) || title;
              // 标记匹配关键词后的内容
              var postContent;
              // 显示内容的长度
              var SHOW_WORD_LENGTH = 200;
              // 命中关键词前的字符显示长度
              var SHOW_WORD_FRONT_LENGTH = 20;
              var SHOW_WORD_END_LENGTH = SHOW_WORD_LENGTH - SHOW_WORD_FRONT_LENGTH;

              // 截取匹配的第一个字符，前后共 200 个字符来显示
              if (contentHitSlice.length > 0) {
                var firstIndex = contentHitSlice[0].index;
                var start = firstIndex > SHOW_WORD_FRONT_LENGTH ? firstIndex - SHOW_WORD_FRONT_LENGTH : 0;
                var end = firstIndex + SHOW_WORD_END_LENGTH;
                postContent = highlightKeyword(content, contentHitSlice, start, end);
              } else { // 未匹配到内容，直接截取前 200 个字符来显示
                postContent = content.slice(0, SHOW_WORD_LENGTH);
              }
              postData.title = postTitle;
              postData.content = postContent;
              postData.url = postURL;
              postData.weight = postWeight;
              matchPosts.push(postData);
            }
          });
        }

        var resultInnerHtml = '';
        if (matchPosts.length) {
          // 按权重递增的顺序排序，使权重大的优先显示
          matchPosts.sort(function (left, right) {
            return right.weight - left.weight;
          });
          resultInnerHtml += '<ul>';
          matchPosts.forEach(function (post) {
            resultInnerHtml += '<li><a class="search-results-title" href="' + post.url + '">';
            resultInnerHtml += post.title;
            resultInnerHtml += '</a><div class="search-results-content">';
            resultInnerHtml += post.content;
            resultInnerHtml += '</div></li>';
          });
          resultInnerHtml += '</ul>';
        } else {
          resultInnerHtml += '<div class="search-results-none"><i class="far fa-meh"></i></div>';
        }
        $result.html(resultInnerHtml);
      };
      $input.on('input', searchPost);
      $input.on('keyup', function (e) {
        if (e.keyCode === Stun.utils.codeToKeyCode('Enter')) {
          searchPost();
        }
      });
    }
  });
}

function closeSearch () {
  $('body').css({ overflow: 'auto' });
  $('.search-popup').css({ display: 'none' });
  $('.search-mask').css({ display: 'none' });
}

window.addEventListener('DOMContentLoaded', function () {
  Stun.utils.pjaxReloadLocalSearch = function () {
    $('.header-nav-search').on('click', function (e) {
      e.stopPropagation();
      $('body').css('overflow', 'hidden');
      $('.search-popup')
        .velocity('stop')
        .velocity('transition.expandIn', {
          duration: 300,
          complete: function () {
            $('.search-popup input').focus();
          }
        });
      $('.search-mask')
        .velocity('stop')
        .velocity('transition.fadeIn', {
          duration: 300
        });

      initSearch();
    });
    $('.search-mask, .search-close').on('click', function () {
      closeSearch();
    });
    $(document).on('keydown', function (e) {
      // Escape <=> 27
      if (e.keyCode === Stun.utils.codeToKeyCode('Escape')) {
        closeSearch();
      }
    });
  };

  Stun.utils.pjaxReloadLocalSearch();
}, false);</script><script src="/js/utils.js?v=2.1.1"></script><script src="/js/stun-boot.js?v=2.1.1"></script><script src="/js/scroll.js?v=2.1.1"></script><script src="/js/header.js?v=2.1.1"></script><script src="/js/sidebar.js?v=2.1.1"></script><script type="application/json" src="/search.xml"></script></body></html>